package main

import (
	"context"
	"fmt"
	"github.com/pkg/errors"
	"golang.org/x/sync/errgroup"
	"net/http"
	"os"
	"os/signal"
	"syscall"
	"time"
)

func main() {
	mux := http.NewServeMux()
	mux.HandleFunc("/hello", func(writer http.ResponseWriter, request *http.Request) {
		_, err := writer.Write([]byte("hello shawJay"))
		if err != nil {
			return
		}
	})
	serverDown := make(chan struct{})
	mux.HandleFunc("/down", func(writer http.ResponseWriter, request *http.Request) {
		serverDown <- struct{}{}
	})

	server := http.Server{
		Addr: ":8070",
		//Addr:    ":3306", //测试端口占用，server.ListenAndServe进程报错的情况
		Handler: mux,
	}

	g, ctx := errgroup.WithContext(context.Background())
	//主要协程，负责http server的启动
	//这个协程的ctx是和g的方法派生出来的，所以这个协程发生错误（比如端口占用），发生error，会对ctx产生cancel函数，ctx结束以后，后面两个协程就可以接受参数停止
	g.Go(func() error {
		return server.ListenAndServe()
	})

	//自己关闭http server
	//用一个同步的select的channel来达到接受关闭信号的准备
	//当接收到关闭信号，调用server.Shutdown，优雅关闭server，然后ctx关闭
	g.Go(func() error {
		select {
		case <-ctx.Done():
			return ctx.Err()
		case <-serverDown:
			downContext, cancel := context.WithTimeout(context.Background(), 3*time.Second)
			defer cancel()
			return server.Shutdown(downContext)
		}
	})

	//负责接受linux的信号 ，主要是ctrl+c带来的 sigint 和 程序退出的 sigterm
	//同上，将自己的信号换成了linux信号
	g.Go(func() error {
		sigs := make(chan os.Signal)
		signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
		select {
		case <-sigs:
			return errors.New("程序接收到信号，退出")
		case <-ctx.Done():
			return ctx.Err()
		}

	})

	if err := g.Wait(); err != nil {
		fmt.Printf("err: %v", err)
		return
	}

}
